// ==================================================================
// @(#)spt.c
//
// Shortest-Path Tree data structure
//
// @author Bruno Quoitin (bruno.quoitin@uclouvain.be)
// @date 20/08/2008
// $Id$
//
// C-BGP, BGP Routing Solver
// Copyright (C) 2002-2008 Bruno Quoitin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
// 02111-1307  USA
// ==================================================================

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <net/node.h>
#include <net/spt.h>
#include <net/subnet.h>

// -----[ _spt_dump_for_each ]---------------------------------------
static int _spt_dump_for_each(uint32_t key, uint8_t key_len,
			      void * item, void * ctx)
{
  ip_pfx_t prefix= { .network= key, .mask= key_len };
  gds_stream_t * stream= (gds_stream_t *) ctx;

  stream_printf(stream, "spt vertex ");
  ip_prefix_dump(stream, prefix);
  return 0;
}

// -----[ spt_dump ]-------------------------------------------------
void spt_dump(gds_stream_t * stream, spt_t * spt)
{
  stream_printf(stream, "\n\n");
  radix_tree_for_each(spt->tree, _spt_dump_for_each, stream);
}

// -----[ spt_vertex_dump ]------------------------------------------
void spt_vertex_dump(gds_stream_t * stream, spt_vertex_t * vertex)
{
  switch (vertex->elem.type) {
  case LINK : net_iface_dump_id(stream, vertex->elem.link); break;
  case NODE  : node_dump_id(stream, vertex->elem.node); break;
  case SUBNET: subnet_dump_id(stream, vertex->elem.subnet); break;
  default:
    abort();
  }
} 

// -----[ spt_to_graphviz ]------------------------------------------
void spt_to_graphviz(gds_stream_t * stream, spt_t * spt)
{
  gds_enum_t * vertices;
  spt_vertex_t * vertex;
  spt_vertex_t * pred;
  unsigned int index;

  stream_printf(stream, "/**\n");
  stream_printf(stream, " * SPT graphviz dot file\n");
  stream_printf(stream, " * generated by C-BGP\n");
  stream_printf(stream, " *\n");
  stream_printf(stream, " * Render with: dot -Tps <file.dot> <file.ps>\n");
  stream_printf(stream, " */\n");
  stream_printf(stream, "digraph G {\n");
  
  vertices= radix_tree_get_enum(spt->tree);
  while (enum_has_next(vertices)) {
    vertex= *((spt_vertex_t **) enum_get_next(vertices));
    stream_printf(stream, "  \"");
    spt_vertex_dump(stream, vertex);
    stream_printf(stream, "\" [");
    stream_printf(stream, "shape=");
    switch (vertex->elem.type) {
    case LINK:
      stream_printf(stream, "ellipse");
      break;
    case NODE:
      stream_printf(stream, "box");
      break;
    case SUBNET:
      stream_printf(stream, "ellipse");
      break;
    default:
      abort();
    }
    if (vertex == spt->root)
      stream_printf(stream, ",style=bold");
    stream_printf(stream, "] ;\n");
    for (index= 0; index < spt_vertices_size(vertex->preds); index++) {
      pred= vertex->preds->data[index];
      stream_printf(stream, "  \"");
      spt_vertex_dump(stream, pred);
      stream_printf(stream, "\" -> \"");
      spt_vertex_dump(stream, vertex);
      stream_printf(stream, "\" [label=%u] ;\n", vertex->weight);
    }
  }
  enum_destroy(&vertices);

  stream_printf(stream, "}\n");
}
